﻿using System;
using System.IO;
using System.Globalization;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Collections;
using System.Diagnostics;
using Coevery.Tasacion.Models;
using Orchard;
using Orchard.ContentManagement;
using Orchard.ContentManagement.Aspects;
using Orchard.ContentManagement.MetaData;
using Orchard.Core.Common.Models;
using Orchard.Core.Title.Models;
using Orchard.Data;
using Orchard.Localization;
using Orchard.Logging;
using Orchard.Security;
using Orchard.UI.Notify;
using Orchard.Utility.Extensions;
using Coevery.Fields.Fields;
using System.Collections.ObjectModel;
using System.Net.Http;
using System.Net.Http.Formatting;
using Coevery.Fields.ViewModels;

using Orchard.Security.Permissions;
using Coevery.Relationship.Fields;

using PrettyGallery.Services;
using PrettyGallery.ViewModels;


namespace Coevery.Tasacion.Services
{
    public class TasacionService : ITasacionService
    {
        private readonly IRepository<InmuebleIdealistaRecord> _tasacionRepository;
        private readonly IRepository<FotoRecord> _fotoRepository;
        private readonly IContentManager _contentManager;
        private readonly INotifier _notifier;
        private readonly IAuthorizationService _authorizationService;
        private readonly IContentDefinitionManager _contentDefinitionManager;
        private readonly IOrchardServices _services;
        private readonly IPrettyGalleryService _prettyGalleryService;

        #region Bing Classes
        public class BingLocationResult
        {
            public string authenticationResultCode { get; set; }
            public string brandLogoUri { get; set; }
            public string copyright { get; set; }
            public Locations[] resourceSets { get; set; }
            public int statusCode { get; set; }
            public string statusDescription { get; set; }
            public string traceId { get; set; }
        }

        public class Locations
        {
            public int estimatedTotal { get; set; }
            public Location[] resources { get; set; }
        }

        public class Location
        {
            public string __type { get; set; }
            public float[] bbox { get; set; }
            public string name { get; set; }
            public Point point { get; set; }
            public Address address { get; set; }
            public string confidence { get; set; }
            public string entityType { get; set; }
            public Geocodepoint[] geocodePoints { get; set; }
            public string[] matchCodes { get; set; }
        }

        public class Point
        {
            public string type { get; set; }
            public float[] coordinates { get; set; }
        }

        public class Address
        {
            public string addressLine { get; set; }
            public string adminDistrict { get; set; }
            public string adminDistrict2 { get; set; }
            public string countryRegion { get; set; }
            public string formattedAddress { get; set; }
            public string locality { get; set; }
            public string postalCode { get; set; }
        }

        public class Geocodepoint
        {
            public string type { get; set; }
            public float[] coordinates { get; set; }
            public string calculationMethod { get; set; }
            public string[] usageTypes { get; set; }
        }
        #endregion

        public TasacionService(
            IRepository<InmuebleIdealistaRecord> tasacionItemContentItemRepository,
            IRepository<FotoRecord> fotoItemContentItemRepository,
            IContentManager contentManager,
            INotifier notifier,
            IContentDefinitionManager contentDefinitionManager,
            IAuthorizationService authorizationService,
            IOrchardServices services,
            IPrettyGalleryService prettyGalleryService)
        {
            _tasacionRepository = tasacionItemContentItemRepository;
            _fotoRepository = fotoItemContentItemRepository;
            _contentManager = contentManager;
            _notifier = notifier;
            _authorizationService = authorizationService;
            _contentDefinitionManager = contentDefinitionManager;
            _services = services;
            _prettyGalleryService = prettyGalleryService;

            Logger = NullLogger.Instance;
            T = NullLocalizer.Instance;
        }


        public ILogger Logger { get; set; }
        public Localizer T { get; set; }


        public void Create(InmuebleIdealistaRecord testigo)
        {
            _tasacionRepository.Create(testigo);
            /*
            foreach (var foto in testigo.fotoes)
            {
                
                _fotoRepository.Create(new FotoRecord
                {
                    Description = "Dummy Description",
                    Img = foto.Img,
                    InmuebleIdealista_Id = testigo.Id
                }
                );
            }
            */
        }

        public void Delete(InmuebleIdealistaRecord testigo)
        {
            throw new NotImplementedException();
        }

        public void Update(InmuebleIdealistaRecord testigo)
        {
            throw new NotImplementedException();
        }


        public void GetAndSavePisosCercanos(ContentItem contentItemVivienda, GeographicalPoint point, string viviendaTitle)
        {

            ContentItem contentItemTasacion = CreateTasacion(contentItemVivienda, viviendaTitle);

            try
            {
                int inmuebleId = contentItemVivienda.Id;
                float lat = point.Latitude;
                float lon = point.Longitude;

                //2. Busco viviendas cercanas
                JsonData respuesta = TasacionDataHelper.buscarInmueblesProximos(lat.ToString(), lon.ToString(), null);
                int i = 0;
                int j = 0;
                int avgPrice_total = 0;
                int avgPrice_acum = 0;
                
                if (respuesta.elementList.Count() > 0)
                    foreach (Element jsonInm in respuesta.elementList)
                    {
                        int avgPrice_cur = 0;
                        j++;
                        ContentItem contentItemTestigo = CreateTestigo(contentItemTasacion, "Testigo " + j + " para vivienda: " + viviendaTitle, jsonInm);

                        ContentPart testigoPart = contentItemTestigo.Parts.Where(p => p.PartDefinition.Name.Contains("Testigo")).FirstOrDefault<ContentPart>();

                        CoeveryTextField priceVal = (CoeveryTextField)testigoPart.Fields.Where(ff => ff.Name.Equals("Price")).FirstOrDefault();
                        CoeveryTextField sizeVal = (CoeveryTextField)testigoPart.Fields.Where(ff => ff.Name.Equals("Size")).FirstOrDefault();

                        if (priceVal.Value != null && sizeVal.Value != null && priceVal.Value != "" && sizeVal.Value != "")
                        {
                            avgPrice_cur = Convert.ToInt32(Double.Parse((string)priceVal.Value) / Double.Parse((string)sizeVal.Value));
                            i++;
                            avgPrice_acum += avgPrice_cur;
                        }
                        
                        string subPath = "~" + Path.DirectorySeparatorChar +
                                    "Media" + Path.DirectorySeparatorChar + "Default" + Path.DirectorySeparatorChar + "SampleMedia" + Path.DirectorySeparatorChar +
                                    contentItemTasacion.Id + Path.DirectorySeparatorChar + contentItemTestigo.Id + Path.DirectorySeparatorChar;

                        string path = HttpContext.Current.Server.MapPath(subPath);

                        TasacionDataHelper.obtenerYGuardarFotos(jsonInm.propertyCode, path);

                        _prettyGalleryService.UpdatePrettyGalleryForContentItem(contentItemTestigo,
                            new EditPrettyGalleryViewModel() {
                                MediaPath = "SampleMedia/" + contentItemTasacion.Id + "/" + contentItemTestigo.Id + "/",
                                ThumbnailWidth = 150,
                                ThumbnailHeight = 150,
                                PrettyParameters = "{\"theme\":\"light_square\",\"overlay_gallery\":false}",
                                Layout = "icons_with_titles"
                            });
                        
                        //break; // WARNING PARA QUE EN PRUEBAS SOLO CREE UN TESTIGO
                    }
                avgPrice_total = avgPrice_acum / i;

                ContentPart tasacionPart = contentItemTasacion.Parts.Where(p => p.PartDefinition.Name.Contains("Tasacion")).FirstOrDefault<ContentPart>();
                NumberField precioTasac = (NumberField)tasacionPart.Fields.Where(ff => ff.Name.Equals("Precio")).First();
                NumberField precioMetroTasac = (NumberField)tasacionPart.Fields.Where(ff => ff.Name.Equals("Preciopormetro")).First();

                //precioTasac.Value = avgPrice_total.ToString();
                precioMetroTasac.Value = avgPrice_total;
                    
                _services.ContentManager.UpdateEditor(contentItemTasacion, null);

                if (!contentItemTasacion.Has<IPublishingControlAspect>())
                {
                    _services.ContentManager.Publish(contentItemTasacion);
                }
                
                
            }
            catch (Exception e)
            {
                Debug.WriteLine("Mirar console...: " + e.Message);
            }
            
        }


        private void Tasar()
        {

            InmuebleIdealistaRecord testigo = new InmuebleIdealistaRecord();
            testigo.AbrAddress = "";

            _tasacionRepository.Create(new InmuebleIdealistaRecord
            {
                Id = 1,
                AbrAddress = "test",
            }
            );
            _tasacionRepository.Flush();
            _tasacionRepository.Delete(_tasacionRepository.Get(r => r.Id == 1));
        }

        public GeographicalPoint GetCoordinates(string comunidadautonoma, string provincia, string municipio,
                                        string codigopostal, string tipovia, string nombrevia, string numero)
        {
            string uri = "http://dev.virtualearth.net/REST/v1/Locations?countryRegion={0}&adminDistrict={1}&locality={2}&postalCode={3}&addressLine={4}&includeNeighborhood=false&maxResults=1&key=Ag8BasusptLtUJoWha0CxRNnV0a28Vn39QOsqnGAmnopvdg6paZfeyMOj9Cobumu";

            string requestUri = string.Format(uri,
            HttpUtility.UrlEncode("España"),          // Pais
            HttpUtility.UrlEncode(comunidadautonoma), // CCAA
            HttpUtility.UrlEncode(municipio),         // Municipio
            HttpUtility.UrlEncode(codigopostal),      // cp
            HttpUtility.UrlEncode(numero + " " +      // Numero
                                  tipovia + " " +     // Tipo Via
                                  nombrevia)          // Nombre Via
                    );

            HttpClient client = new HttpClient();
            var response = client.GetAsync(requestUri).Result;
            var result = response.Content.ReadAsAsync<BingLocationResult>().Result;
            // and now the processing of the result...            

            double lat = result.resourceSets[0].resources[0].geocodePoints[0].coordinates[0];
            double lon = result.resourceSets[0].resources[0].geocodePoints[0].coordinates[1];

            return new GeographicalPoint((float)lat, (float)lon);
        }

        /*
        private async void GetCoordinatesAsync(string comunidadautonoma, string provincia, string municipio,
                                string tipovia, string nombrevia, string numero)
        {
            string uri = "http://dev.virtualearth.net/REST/v1/Locations?countryRegion={0}&adminDistrict={1}&locality={2}&postalCode={3}&addressLine={4}&includeNeighborhood=false&maxResults=1&key=Ag8BasusptLtUJoWha0CxRNnV0a28Vn39QOsqnGAmnopvdg6paZfeyMOj9Cobumu";

            string requestUri = string.Format(uri,
            HttpUtility.UrlEncode("España"),          // Pais
            HttpUtility.UrlEncode(comunidadautonoma), // CCAA
            HttpUtility.UrlEncode(provincia),         // Provincia
            HttpUtility.UrlEncode(municipio),         // Municipio
            HttpUtility.UrlEncode(numero + " " +      // Numero
                                  tipovia + " " +     // Tipo Via
                                  nombrevia)          // Nombre Via
                    );

            HttpClient client = new HttpClient();
            var response = await client.GetAsync(requestUri);
            var result = await  response.Content.ReadAsAsync<BingLocationResult>();
            // and now the processing of the result...            

            double lat = result.resourceSets[0].resources[0].geocodePoints[0].coordinates[0];
            double lon = result.resourceSets[0].resources[0].geocodePoints[0].coordinates[1];
        }
         */

        private static void SetPropertyValue(object obj, string propertyName, object value)
        {
            System.Reflection.PropertyInfo info = obj.GetType().GetProperty(propertyName);
            if (info == null) return;
            info.SetValue(obj, value, null);
        }

        private static object GetPropertyValue(object obj, string propertyName)
        {
            System.Reflection.PropertyInfo info = obj.GetType().GetProperty(propertyName);
            if (info == null) return null;
            return info.GetValue(obj, null);
        }

        private ContentItem CreateTasacion(ContentItem viviendaContentItem, string viviendaTitle)
        {
            //////////////////////////////////////////////
            //          Creo una TASACION               //
            //////////////////////////////////////////////

            var contentItemTasacion = _services.ContentManager.New("Tasacion");

            _services.ContentManager.Create(contentItemTasacion, VersionOptions.Draft);
            //Services.ContentManager.Create(contentItem, VersionOptions.Latest);

            ContentPart tasacionPart = contentItemTasacion.Parts.Where(p => p.PartDefinition.Name.Contains("Tasacion")).FirstOrDefault<ContentPart>();
            ReferenceField viviendaRefFld = (ReferenceField)tasacionPart.Fields.Where(ff => ff.Name.Equals("Vivienda")).First();
            viviendaRefFld.ContentItemField.Value = viviendaContentItem;
            viviendaRefFld.ContentItem = viviendaContentItem;
            viviendaRefFld.Value = viviendaContentItem.Id;

            CoeveryTextField tasac = (CoeveryTextField)tasacionPart.Fields.Where(ff => ff.Name.Equals("Tasacion")).First();

            tasac.Value = "Tasacion para " + viviendaTitle + " (" + DateTime.Now.ToLongDateString() + ")"; ;

            _services.ContentManager.UpdateEditor(contentItemTasacion, null);

            if (!contentItemTasacion.Has<IPublishingControlAspect>())
            {
                _services.ContentManager.Publish(contentItemTasacion);
            }

            return contentItemTasacion;


        }

        private ContentItem CreateTestigo(ContentItem contentItemTasacion, string testigoTitle, Element jsonInm)
        {

            //Falta dar de alta por pantalla Floor y ProperyType
            var contentItemTestigo = _services.ContentManager.New("Testigo");

            _services.ContentManager.Create(contentItemTestigo, VersionOptions.Draft);
            //Services.ContentManager.Create(contentItem, VersionOptions.Latest);

            ContentPart testigoPart = contentItemTestigo.Parts.Where(p => p.PartDefinition.Name.Contains("Testigo")).FirstOrDefault<ContentPart>();
            IEnumerable<ContentField> fields = testigoPart.Fields;//.Where(ff => !ff.Name.Equals("Testigo"));
            foreach (ContentField fld in fields)
            {
                string input = fld.Name.First().ToString().ToLower() + String.Join("", fld.Name.Skip(1));
                fld.Storage.Set(fld.Name, GetPropertyValue(jsonInm, input));
            }

            ReferenceField tasacionRefFld = (ReferenceField)testigoPart.Fields.Where(ff => ff.Name.Contains("Tasacion")).First();
            tasacionRefFld.ContentItem = contentItemTasacion;
            tasacionRefFld.ContentItemField.Value = contentItemTasacion;
            tasacionRefFld.Value = contentItemTasacion.Id;

            CoeveryTextField testigo = (CoeveryTextField)testigoPart.Fields.Where(ff => ff.Name.Equals("Testigo")).First();
            testigo.Value = testigoTitle + " (" + DateTime.Now.ToShortDateString() + ")";

            _services.ContentManager.UpdateEditor(contentItemTestigo, null);

            if (!contentItemTestigo.Has<IPublishingControlAspect>())
            {
                _services.ContentManager.Publish(contentItemTestigo);
            }

            //createFolder(contentItemTasacion.Id, contentItemTestigo.Id);

            createFolder(contentItemTasacion.Id, contentItemTestigo.Id);

            return contentItemTestigo;
        }

        private string GetFieldValue(IEnumerable<ContentField> fields, string key)
        {
            ContentField field = fields.FirstOrDefault(x => x.Name == key);
            string result = GetPropertyValue(field, "Value").ToString();
            return result;
        }

        private void createFolder(int tasacionId, int testigoId)
        {
            //string subPath = "/SampleMedia/" + tasacionId + "/" + testigoId; // your code goes here
            //System.Web.HttpContext.Current.Server.MapPath(path);
            //System.Web.Hosting.HostingEnvironment.MapPath(path);

            string subPath = "~" + Path.DirectorySeparatorChar +
                "Media" + Path.DirectorySeparatorChar + "Default" + Path.DirectorySeparatorChar + "SampleMedia" + Path.DirectorySeparatorChar +
                tasacionId + Path.DirectorySeparatorChar + testigoId + Path.DirectorySeparatorChar;

            bool exists = System.IO.Directory.Exists(HttpContext.Current.Server.MapPath(subPath));

            if (!exists)
                System.IO.Directory.CreateDirectory(HttpContext.Current.Server.MapPath(subPath));
            else 
            {//delete content
                
                System.IO.DirectoryInfo downloadedMessageInfo = new DirectoryInfo(HttpContext.Current.Server.MapPath(subPath));
                foreach (FileInfo file in downloadedMessageInfo.GetFiles())
                {
                    file.Delete();
                }
                foreach (DirectoryInfo dir in downloadedMessageInfo.GetDirectories())
                {
                    dir.Delete(true);
                }
            }
        }

    }
}
